import * as path from 'path';
import * as fs from 'fs';
import { Logger } from '../../../../src/logger/Logger';
import { BaseLLM } from '../../../../core/llm/baseLLM';
import { FuzzerContext, FileGenerationResult } from '../types/FuzzTypes';
import { FuzzPromptBuilder } from './FuzzPromptBuilder';
import { FuzzProjectAnalyzer } from './FuzzProjectAnalyzer';
import { FuzzNameUtils } from '../utils/FuzzNameUtils';

/**
 * Fuzz 文件生成器
 * 负责逐个文件调用 LLM 生成代码
 */
export class FuzzFileGenerator {
    private sendMessage: (msg: any) => void;
    private currentAbortController: AbortController | null = null;
    private isPaused: boolean = false;
    private pausePromiseResolver: (() => void) | null = null;

    constructor(sendMessage: (msg: any) => void) {
        this.sendMessage = sendMessage;
    }

    /**
     * 设置暂停/继续/取消控制器
     */
    public setControlState(
        abortController: AbortController | null,
        isPaused: boolean,
        pauseResolver: (() => void) | null
    ): void {
        this.currentAbortController = abortController;
        this.isPaused = isPaused;
        this.pausePromiseResolver = pauseResolver;
    }

    /**
     * 等待暂停状态解除
     */
    private async waitIfPaused(): Promise<void> {
        if (this.isPaused) {
            Logger.info('[FuzzFileGenerator] ⏸️  暂停中，等待用户操作...');
            await new Promise<void>((resolve) => {
                this.pausePromiseResolver = resolve;
            });
            Logger.info('[FuzzFileGenerator] ▶️  已继续');
        }
    }

    /**
     * 逐个文件生成 Fuzz 测试
     */
    public async generateAllFiles(
        llm: BaseLLM,
        context: FuzzerContext
    ): Promise<void> {
        const { fuzzerName, fuzzerDir, projectRoot } = context;
        const baseName = FuzzNameUtils.getBaseName(context.sourceFile);
        const relativeFuzzerPath = FuzzProjectAnalyzer.getRelativeFuzzerPath(projectRoot, fuzzerDir);

        // 🔍 解析源文件的依赖（头文件、成员变量定义等）
        let enhancedSourceCode = context.sourceCode;
        try {
            const { DependencyResolver } = await import('../../UnitTest/DependencyResolver');
            const dependencies = await DependencyResolver.resolveDependencies(
                context.sourceFile,
                context.sourceCode
            );
            
            if (dependencies.length > 0) {
                Logger.info(`[FuzzFileGenerator] 📎 找到 ${dependencies.length} 个依赖头文件`);
                
                // 格式化依赖，追加到源代码
                let depContext = `\n\n// ===== 依赖的头文件（${dependencies.length}个）=====\n`;
                depContext += `// 包含类定义、成员变量、函数声明等\n\n`;
                
                for (const dep of dependencies) {
                    depContext += `// --- ${dep.type}: ${dep.fileName} ---\n`;
                    if (dep.content) {
                        const lines = dep.content.split('\n');
                        if (lines.length > 300) {
                            depContext += `${lines.slice(0, 300).join('\n')}\n`;
                            depContext += `// ... (已截断，共 ${lines.length} 行)\n\n`;
                        } else {
                            depContext += `${dep.content}\n\n`;
                        }
                    } else {
                        depContext += `// (文件过大)\n\n`;
                    }
                }
                
                enhancedSourceCode = context.sourceCode + depContext;
                Logger.info(`[FuzzFileGenerator] ✅ 已增强源代码上下文`);
            }
        } catch (error) {
            Logger.warn(`[FuzzFileGenerator] ⚠️ 依赖解析失败，使用原始源代码: ${error}`);
        }

        // === 1. 生成 .h 文件 ===
        await this.generateSingleFile(
            llm,
            `${fuzzerName}.h`,
            fuzzerDir,
            FuzzPromptBuilder.buildHeaderPrompt(fuzzerName),
            'cpp'
        );

        // === 2. 生成 .cpp 文件（使用增强后的源代码）===
        await this.generateSingleFile(
            llm,
            `${fuzzerName}.cpp`,
            fuzzerDir,
            FuzzPromptBuilder.buildCppPrompt(
                fuzzerName,
                baseName,
                enhancedSourceCode,  // 包含依赖头文件的完整上下文
                context.sourceGNConfig
            ),
            'cpp'
        );

        // === 3. 生成 BUILD.gn（使用智能推理引擎） ===
        await this.generateSingleFile(
            llm,
            'BUILD.gn',
            fuzzerDir,
            FuzzPromptBuilder.buildBuildGnPrompt(
                fuzzerName,
                context.projectInfo,
                relativeFuzzerPath,
                context.sourceGNConfig,
                context.sourceCode  // 传递源代码，启用智能推断
            ),
            'python'
        );

        // === 4. 生成 project.xml ===
        await this.generateSingleFile(
            llm,
            'project.xml',
            fuzzerDir,
            FuzzPromptBuilder.buildProjectXmlPrompt(),
            'xml'
        );

        // === 5. 生成 corpus/init ===
        const corpusDir = path.join(fuzzerDir, 'corpus');
        if (!fs.existsSync(corpusDir)) {
            fs.mkdirSync(corpusDir, { recursive: true });
        }
        
        await this.generateSingleFile(
            llm,
            'corpus/init',
            fuzzerDir,
            FuzzPromptBuilder.buildCorpusInitPrompt(),
            'text'
        );

        this.sendMessage({
            type: 'success',
            content: `🎉 **所有文件生成完成！**\n\n共生成 5 个文件：\n` +
                    `- ${fuzzerName}.h\n` +
                    `- ${fuzzerName}.cpp\n` +
                    `- BUILD.gn\n` +
                    `- project.xml\n` +
                    `- corpus/init`
        });
    }

    /**
     * 生成单个文件
     */
    private async generateSingleFile(
        llm: BaseLLM,
        fileName: string,
        fuzzerDir: string,
        prompt: string,
        language: string
    ): Promise<FileGenerationResult> {
        const filePath = fileName.includes('/') 
            ? path.join(fuzzerDir, fileName) 
            : path.join(fuzzerDir, fileName);

        try {
            this.sendMessage({
                type: 'info',
                content: `📝 **正在生成：${fileName}**\n\n⏳ LLM 正在思考...`
            });

            // 创建新的 AbortController 用于这个文件的生成
            if (!this.currentAbortController) {
                this.currentAbortController = new AbortController();
            }

            let generatedCode = '';
            let chunkCount = 0;

            // 流式接收 LLM 响应
            const stream = llm._streamChat([
                { role: 'user', content: prompt }
            ], this.currentAbortController.signal);

            for await (const chunk of stream) {
                // 检查是否被取消
                if (this.currentAbortController?.signal.aborted) {
                    throw new Error('用户取消操作');
                }
                
                // 检查是否暂停
                await this.waitIfPaused();
                
                if (chunk.content && typeof chunk.content === 'string') {
                    generatedCode += chunk.content;
                    chunkCount++;
                    
                    // 每50个块显示一次进度
                    if (chunkCount % 50 === 0) {
                        this.sendMessage({
                            type: 'text-chunk',
                            content: generatedCode,
                            isPartial: true
                        });
                    }
                }
            }

            // === 显示完整生成的代码 ===
            this.sendMessage({
                type: 'text',
                content: `\`\`\`${language}\n${generatedCode}\n\`\`\``
            });

            // === 保存文件 ===
            fs.writeFileSync(filePath, generatedCode, 'utf-8');
            const fileSize = fs.statSync(filePath).size;

            Logger.info(`[FuzzFileGenerator] ✅ 已保存: ${filePath} (${fileSize} 字节)`);

            this.sendMessage({
                type: 'file-created',
                content: `✅ **已创建：${fileName}**（${fileSize} 字符）`,
                filePath
            });

            return {
                success: true,
                filePath,
                fileSize
            };

        } catch (error: any) {
            Logger.error(`[FuzzFileGenerator] ❌ 生成 ${fileName} 失败: ${error.message || error}`);
            
            this.sendMessage({
                type: 'error',
                content: `❌ **生成 ${fileName} 失败**\n\n${error.message}`
            });

            return {
                success: false,
                filePath,
                fileSize: 0,
                error: error.message
            };
        }
    }

    /**
     * 在Fuzz函数前添加"采纳 | 拒绝"选项
     */
    private addAcceptRejectOptions(code: string): string {
        // 匹配 LLVMFuzzerTestOneInput 函数定义
        // 可能的模式：
        // 1. extern "C" int LLVMFuzzerTestOneInput(...)
        // 2. int LLVMFuzzerTestOneInput(...)
        const functionPattern = /(extern\s+"C"\s+)?int\s+LLVMFuzzerTestOneInput\s*\(/;
        
        const lines = code.split('\n');
        const result: string[] = [];
        
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            
            // 如果匹配到Fuzz函数定义，在它前面添加选项
            if (functionPattern.test(line)) {
                // 检查上一行是否已经有选项标记（避免重复添加）
                const prevLine = i > 0 ? lines[i - 1].trim() : '';
                if (!prevLine.includes('[采纳]') && !prevLine.includes('[拒绝]')) {
                    result.push('// 👉 [采纳] | [拒绝] 👈  请删除不需要的选项');
                }
            }
            
            result.push(line);
        }
        
        return result.join('\n');
    }
}

